package com.server.entity;

import com.register.client.domian.ClientServiceInstance;
import com.register.client.domian.HeartBeat;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * 注册表
 * 后面改造为并发安全的
 * 单例的,里面维护了服务名 : 服务实例:ip等信息
 */
@Data
public class Registry {

    /**
     * 核心注册表结构
     * 服务名:{
     * 服务实例Id:服务实例
     * }
     */
    private Map<String, Map<String, ServiceInstance>> registryMap = new HashMap<>();

    /**
     * 双重锁优化
     */
    private static volatile Registry instance;

    /**
     * 最近变更的服务实例
     */
    private LinkedList<RecentlyChangedServiceInstance> recentlyChangedQueue = new LinkedList<>();


    /**
     * 获取服务注册表的单例实例
     *
     * @return
     */
    public static Registry getInstance() {
        if (instance == null) {
            synchronized (Registry.class) {
                if (instance == null) {
                    instance = new Registry();
                }
            }
        }
        return instance;
    }

    public Registry() {
    }


    /**
     * 注册表删除服务实例
     */
    public synchronized void remove(String ServiceName, String serviceInstanceId) {
        Map<String, ServiceInstance> instanceMap = registryMap.get(ServiceName);
        ServiceInstance serviceInstance = instanceMap.get(serviceInstanceId);
        //写入最近改变的队列中
        RecentlyChangedServiceInstance changedServiceInstance = convertToChangedServiceInstance(serviceInstance, ServiceInstanceOperation.REMOVE);
        instance.recentlyChangedQueue.add(changedServiceInstance);

        //删除实例
        instanceMap.remove(serviceInstanceId);
    }

    /**
     * 获取服务注册表
     *
     * @return
     */
    public Map<String, Map<String, ServiceInstance>> getRegistry() {

        return registryMap;
    }

    /**
     * 服务注册
     */
    public synchronized void registry(ServiceInstance serviceInstance) {
        Map<String, ServiceInstance> serviceInstanceMap = instance.registryMap.get(serviceInstance.getServiceName());
        //如果不存在,就set
        if (serviceInstanceMap == null) {
            serviceInstanceMap = new HashMap<String, ServiceInstance>();
            serviceInstanceMap.put(serviceInstance.getServiceInstanceId(), serviceInstance);
            instance.registryMap.put(serviceInstance.getServiceName(), serviceInstanceMap);
            //写入最近改变的队列中
            addRecentlyChangedByRegister(serviceInstance,ServiceInstanceOperation.REGISTER);
            return;
        }
        //服务名已经存在
        serviceInstanceMap.put(serviceInstance.getServiceInstanceId(), serviceInstance);
        instance.registryMap.put(serviceInstance.getServiceName(), serviceInstanceMap);

        //写入最近改变的队列中
        addRecentlyChangedByRegister(serviceInstance,ServiceInstanceOperation.REGISTER);

    }

    private void addRecentlyChangedByRegister(ServiceInstance serviceInstance, String register) {
        RecentlyChangedServiceInstance changedServiceInstance = convertToChangedServiceInstance(serviceInstance, register);
        instance.recentlyChangedQueue.add(changedServiceInstance);
    }

    private RecentlyChangedServiceInstance convertToChangedServiceInstance(ServiceInstance serviceInstance, String operation) {
        RecentlyChangedServiceInstance changedServiceInstance = new RecentlyChangedServiceInstance();
        changedServiceInstance.setChangedTimestamp(System.currentTimeMillis());
        changedServiceInstance.setServiceInstance(serviceInstance);
        changedServiceInstance.setServiceInstanceOperation(operation);
        return changedServiceInstance;
    }

    /**
     * 获取服务实例
     */
    public synchronized ServiceInstance getServiceInstance(HeartBeat heartBeat) {
        Map<String, ServiceInstance> serviceInstanceMap = instance.registryMap.get(heartBeat.getServerName());
        if (serviceInstanceMap != null) {
            ServiceInstance serviceInstance = serviceInstanceMap.get(heartBeat.getServiceInstanceId());
            return serviceInstance;
        }
        return null;
    }

    /**
     * 获取整个服务的注册表
     *
     * @return
     */
    public synchronized Map<String, Map<String, ServiceInstance>> getRegistryMap() {
        return registryMap;
    }

    /**
     * 获取增量的注册表
     *
     * @return
     */
    public synchronized Map<String, Map<String, ClientServiceInstance>> getIncrementalRegistryMap() {
        Map<String, Map<String, ClientServiceInstance>> incrementalRegistryMap = new HashMap<>();
        LinkedList<RecentlyChangedServiceInstance> recentlyChangedQueue = instance.recentlyChangedQueue;

        if (!CollectionUtils.isEmpty(recentlyChangedQueue)) {
            for (RecentlyChangedServiceInstance changedServiceInstance : recentlyChangedQueue) {
                ServiceInstance serviceInstance = changedServiceInstance.getServiceInstance();
                ClientServiceInstance clientServiceInstance = converToClientInstance(serviceInstance);
                clientServiceInstance.setServiceInstanceOperation(changedServiceInstance.getServiceInstanceOperation());
                if (incrementalRegistryMap.get(serviceInstance.getServiceName()) == null) {
                    Map<String, ClientServiceInstance> clientServiceInstanceMap = new HashMap<>();
                    clientServiceInstanceMap.put(serviceInstance.getServiceInstanceId(), clientServiceInstance);
                    incrementalRegistryMap.put(serviceInstance.getServiceName(), clientServiceInstanceMap);
                    continue;
                }
                Map<String, ClientServiceInstance> clientServiceInstanceMap = incrementalRegistryMap.get(serviceInstance.getServiceName());
                clientServiceInstanceMap.put(serviceInstance.getServiceInstanceId(), clientServiceInstance);

            }
        }

        return incrementalRegistryMap;
    }

    private ClientServiceInstance converToClientInstance(ServiceInstance serviceInstance) {
        ClientServiceInstance clientServiceInstance = new ClientServiceInstance();
        BeanUtils.copyProperties(serviceInstance, clientServiceInstance);
        return clientServiceInstance;
    }


    /**
     * 最近变更的服务实例
     */
    @Data
    class RecentlyChangedServiceInstance {
        /**
         * 服务实例
         */
        ServiceInstance serviceInstance;

        /**
         * 时间戳
         */
        Long changedTimestamp;

        /**
         * 操作表示
         * 注册 : REGISTER
         * 删除 : REMOVE
         */
        String serviceInstanceOperation;

    }

    class ServiceInstanceOperation {
        //注册
        public static final String REGISTER = "REGISTER";
        //删除
        public static final String REMOVE = "REMOVE";


    }
}
